package com.pm.common.impl;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.yitter.idgen.YitIdHelper;
import com.github.yulichang.query.MPJLambdaQueryWrapper;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.pm.buglist.domain.SysFiles;
import com.pm.buglist.mapper.SysFilesMapper;
import com.pm.common.OAService;
import com.pm.common.annotation.DataSource;
import com.pm.common.config.ParamConfig;
import com.pm.common.constant.ProjectConstants;
import com.pm.common.core.domain.AjaxResult;
import com.pm.common.core.domain.entity.Attachment;
import com.pm.common.core.domain.entity.ProjectListNodeMember;
import com.pm.common.core.domain.entity.Review;
import com.pm.common.core.domain.entity.SysUser;
import com.pm.common.core.domain.model.LoginUser;
import com.pm.common.enums.*;
import com.pm.common.mapper.OaMapper;
import com.pm.common.utils.DateUtils;
import com.pm.common.utils.OaUtils;
import com.pm.common.utils.SecurityUtils;
import com.pm.common.utils.StringUtils;
import com.pm.common.utils.file.FileUploadUtils;
import com.pm.project.domain.*;
import com.pm.project.domain.vo.ProjectListNodeMemberVO;
import com.pm.project.domain.vo.ProjectListVO;
import com.pm.project.mapper.*;
import com.pm.project.service.ProjectListService;
import com.pm.system.domain.SysConfig;
import com.pm.system.mapper.SysConfigMapper;
import com.pm.system.mapper.SysUserMapper;
import lombok.extern.log4j.Log4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.*;

@Service
public class OAServiceImpl implements OAService {

    Logger logger = LoggerFactory.getLogger(OAServiceImpl.class);

    @Resource
    RestTemplate restTemplate;

    @Resource
    OaMapper oaMapper;

    @Resource
    ParamConfig paramConfig;

    @Resource
    SysConfigMapper sysConfigMapper;

    @Resource
    ProjectListNodeMapper projectListNodeMapper;

    @Resource
    ProjectListNodeMemberOaMapper projectListNodeMemberOaMapper;

    @Resource
    ProjectListNodeMemberMapper projectListNodeMemberMapper;


    @Resource
    ProjectListMemberMapper projectListMemberMapper;

    @Resource
    ProjectListMapper projectListMapper;

    @Resource
    OaUtils oaUtils;

    @Resource
    SysFilesMapper sysFileMapper;

    @Resource
    SysUserMapper sysUserMapper;

    @Resource
    ProjectModifyRecordMapper projectModifyRecordMapper;

    @Resource
    ProjectListService projectListService;



    @Override
    @DataSource(DataSourceType.OA)
    public AjaxResult signLoginToEkp(String oaId) {
        String requestPage = paramConfig.getOaAddr()+ProjectConstants.EKP_DETAIL+oaId;
        return signLoginToEkpUrl(requestPage);
    }

    @Override
    @DataSource(DataSourceType.OA)
    public AjaxResult signLoginToEkpUrl(String requestPage) {

        LoginUser  loginUser = SecurityUtils.getLoginUser();
        String userNo = loginUser.getUser().getJobNumber();
        //查询OA用户登录名
        JSONObject oaUserInfo = oaMapper.getOaUserInfoByUserNo(userNo);

        //OA请求参数
        MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
        param.add("loginName",oaUserInfo.getString("loginName"));

        param.add("requestPage",requestPage);

        String url = paramConfig.getOaAddr()+ ProjectConstants.SIGN_TO_EKP;
        logger.info("单点登录到OA请求参数:"+param.toString());

        HttpHeaders headers = new HttpHeaders();
        String authentication = paramConfig.getOaLoginName()+":"+paramConfig.getOaPassWord();
        String credential = Base64.getEncoder().encodeToString(authentication.getBytes());
        //设置登录权限认证
        headers.set("Authorization",credential);
        //表单的形式请求
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        //请求参数与请求头封装
        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(param, headers);

        JSONObject res = restTemplate.postForObject(url,requestEntity,JSONObject.class);
        logger.info("单点登录到OA返回参数:"+res.toJSONString());

        //是否成功！
        if(res.getBoolean("success")){
            return AjaxResult.success(res.getJSONObject("data"));
        }else{
            logger.error("请求OA单点登录失败:"+res.toJSONString());
            return AjaxResult.error(res.getString("message"));
        }
    }

    @Override
    @Transactional
    public void projectStageReview(JSONObject jsonObject) {

        projectListMemberMapper.projectFileMoreBackStatus(jsonObject);
        if(jsonObject.getIntValue("status") == 10){
            ProjectListNodeMemberOa projectListNodeMemberOa = new ProjectListNodeMemberOa();
            projectListNodeMemberOa.setProjectListNodeMemberId(jsonObject.getLong("projectListNodeMemberId"));
            projectListNodeMemberOa.setStatus(jsonObject.getIntValue("status"));
            projectListNodeMemberOa.setOaId(jsonObject.getString("oaId"));
            projectListNodeMemberOa.setOaNo(jsonObject.getString("oaNo"));
            projectListNodeMemberOa.setType(0);
            projectListNodeMemberOaMapper.insert(projectListNodeMemberOa);

            //设置完成时间
            jsonObject.put("endTime",new Date());

            ProjectListVO projectListVO = projectListNodeMapper.queryProjectInfo(jsonObject.getString("projectListNodeMemberId"));

            //用时天数
            int dayNum = DateUtils.differentDaysByMillisecond(DateUtils.dateTime(DateUtils.YYYY_MM_DD,projectListVO.getStartTime()),new Date());
            jsonObject.put("dayNum",dayNum);
            //是否超时
            int count = DateUtils.differentDaysByMillisecond(DateUtils.dateTime(DateUtils.YYYY_MM_DD,projectListVO.getEndTime()),new Date());
            jsonObject.put("overdue",count<=0?0:count);

            //计算项目进度
            checkProjectDone(projectListVO);
        }



    }

    @Override
    public void projectModifyProcessStatus(JSONObject jsonObject) {

        ProjectModifyRecord projectModifyRecord = new ProjectModifyRecord();
        projectModifyRecord.setOaNo(jsonObject.getString("oaNo"));

        projectModifyRecord.setStatus(jsonObject.getIntValue("status"));
        projectModifyRecord.setUpdateTime(new Date());

        QueryWrapper<ProjectModifyRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("oa_id",jsonObject.getString("oaId"));
        projectModifyRecordMapper.update(projectModifyRecord,queryWrapper);

        MPJLambdaWrapper<ProjectModifyRecord> qw = new MPJLambdaWrapper();
        qw.eq(ProjectModifyRecord::getOaId,jsonObject.getString("oaId"));
        ProjectModifyRecord res = projectModifyRecordMapper.selectOne(qw);


        if(jsonObject.getIntValue("status") == 10){
            if("10".equals(res.getType())){//变更时间
                List<ProjectModifyRecord> list = projectModifyRecordMapper.selectList(queryWrapper);
                if(!CollectionUtils.isEmpty(list)){
                    ProjectModifyRecord item = list.get(0);
                    List<ProjectModifyRecordDetail> details =  projectModifyRecordMapper.queryProjectModifyRecordDetail(item);
                    if(!CollectionUtils.isEmpty(details)){
                        for (ProjectModifyRecordDetail detail : details) {
                            projectListNodeMapper.updateMemberTime(detail);

                            ProjectListNode projectListNode = projectListNodeMapper.selectById(detail.getPnId());
                            List<Long> pnIds = projectListNodeMapper.queryUpdatePnIds(projectListNode);

                            if(!CollectionUtils.isEmpty(pnIds)){
                                JSONObject param = new JSONObject();
                                param.put("pnIds",pnIds);
                                param.put("startTime",detail.getNewStartTime());
                                param.put("endTime",detail.getNewEndTime());
                                projectListNodeMapper.updateChildrenMemberTime(param);
                            }

                        }

                    }
                }
            }else{//变更项目经理

                //变更前的项目经理
                Long projectManager = projectListMapper.selectById(res.getProjectListId()).getProjectManager();
                //变更后的项目经理
                String modifyProjectManagerId = jsonObject.getString("modifyProjectManagerId");
                if(StringUtils.isNotBlank(modifyProjectManagerId)){
                    //变更项目列表项目经理
                    ProjectList projectList = new ProjectList();
                    projectList.setId(res.getProjectListId());
//                    projectList.setCreateBy(Long.valueOf(modifyProjectManagerId));
                    projectList.setProjectManager(Long.valueOf(modifyProjectManagerId));
                    projectListMapper.updateById(projectList);

                    //更新成员表
                    ProjectListMember projectListMember = new ProjectListMember();
                    projectListMember.setProjectListId(res.getProjectListId());
                    projectListMember.setUserId(Long.valueOf(modifyProjectManagerId));
                    MPJLambdaWrapper<ProjectListMember> uw = new MPJLambdaWrapper();
                    uw.eq(ProjectListMember::getProjectListId,res.getProjectListId());
                    uw.eq(ProjectListMember::getType, PostCode.PJM);
                    projectListMemberMapper.update(projectListMember,uw);

                    //更新任务表
                    ProjectListNodeMember projectListNodeMember = new ProjectListNodeMember();
                    projectListNodeMember.setUserId(Long.valueOf(modifyProjectManagerId));
                    projectListNodeMember.setProjectListId(res.getProjectListId());
                    projectListNodeMember.setOldUserId(projectManager);
                    projectListNodeMemberMapper.updateTaskUser(projectListNodeMember);

                }

            }

        }

    }




    @Override
    @DataSource(DataSourceType.OA)
    public String queryProcessStatus(String oaId) {
        return oaMapper.queryProcessStatus(oaId);
    }

    @Override
    public AjaxResult createWaitTaskNotice(String redirect, List<JSONObject> toUsers, String subject) {


            JSONObject param = new JSONObject();
            param.put("appName", ProjectConstants.PM);
            param.put("modelName",ProjectConstants.OA_TODO_MODEL_NAME);
            param.put("modelId",ProjectConstants.OA_TODO_MODEL_ID);
            param.put("subject",subject);
            String url = paramConfig.getOaAddr()+"/pro/sso/proSsoRequest.do?method=login&service="+ URLEncoder.encode(paramConfig.getPmAddr() +"/login?redirect="+redirect) ;
            param.put("link", url);
            param.put("mobileLink",url);
            param.put("padLink",url);
            param.put("type","1");

            param.put("targets",JSONObject.toJSONString(toUsers));
            param.put("createTime", DateUtils.dateTimeNow(DateUtils.YYYY_MM_DD_HH_MM_SS));

            return sendTodo(param);


    }


    /**
     * 启动OA项目文件审批流程
     * @param projectNodeMemberId
     * @return
     */
    @Override
    public AjaxResult addFileProcess(String projectNodeMemberId, String remark, List<Attachment> attachmentForms,int type) {

        ProjectListVO projectListVO =  projectListNodeMapper.queryProjectInfo(projectNodeMemberId);

        LoginUser loginUser = SecurityUtils.getLoginUser();

        //获取配置的模版ID
        Review review = new Review();

        //查询是否已经在模版中配置了OA模板ID
        JSONObject temp = projectListNodeMapper.queryOATempleteId(projectNodeMemberId);

        if(type ==1 || temp== null || StringUtils.isBlank(temp.getString("oaTempleteId"))){//如无模板ID 则从配置中取 //文档变更默认走单文件审核
            SysConfig sysConfig = new SysConfig();
            sysConfig.setConfigKey(ProjectConstants.OA_PROJECT_FILE_PROCESS);
            SysConfig config = sysConfigMapper.selectConfig(sysConfig);
            review.setFdTemplateId(config.getConfigValue());
        }else{
            //如已经配置 则是多节点审批 需要带入审核人
            review.setFdTemplateId(temp.getString("oaTempleteId"));

            List<JSONObject> approveList = projectListNodeMapper.queryApproveList(temp);
            JSONObject flowParam = new JSONObject();
            flowParam.put("auditNote","同意");
            flowParam.put("futureNodeId","N1");

            List<String> changeNodeHandlers = new ArrayList<>();
            if(!CollectionUtils.isEmpty(approveList)){
                for(int i=0;i<approveList.size();i++){
                    String key = "N"+(i+5);
                    String item = key+":"+approveList.get(i).getString("oaUserId");
                    changeNodeHandlers.add(item);
                }
            }

            flowParam.put("changeNodeHandlers",changeNodeHandlers);
            review.setFlowParam(flowParam);
        }

        review.setDocStatus(ProjectConstants.OA_STATUS_WAIT_APPROVE);
        //提交人工号
        JSONObject creator = new JSONObject();
        creator.put("LoginName",loginUser.getUser().getJobNumber());
        review.setDocCreator(creator.toJSONString());
        //流程标题

        review.setFdNumber(UUID.randomUUID().toString());
        JSONObject formValues = new JSONObject();
        formValues.put("fd_3dc7ebab42153e",projectListVO.getProjectName());
        formValues.put("fd_3ded17d92634b4",projectListVO.getProjectNo());
        formValues.put("fd_3dc7ebadbca166",projectListVO.getProjectManagerName());
        formValues.put("fd_3dc7ebaee9caac",projectListVO.getEndTime());
        formValues.put("fd_3dc7ebaff9fa12",remark);

        // logger.info("启动OA项目文件审批流程请求参数:"+JSONObject.toJSONString(review));
        String oaNo = projectListVO.getTaskNo();
        String title = projectListVO.getProjectNo()+"__"+projectListVO.getNodeName();

        //如果是变更  则先查出变更次数
        if(type ==1){
            QueryWrapper<ProjectListNodeMemberOa> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("project_list_node_member_id",projectNodeMemberId);
            queryWrapper.eq("type",1);
            int count = projectListNodeMemberOaMapper.selectCount(queryWrapper);
            oaNo = projectListVO.getTaskNo()+"_U"+(count+1);
            title = title+" 第"+(count+1)+"次变更";
        }else{
            QueryWrapper<ProjectListNodeMemberOa> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("project_list_node_member_id",projectNodeMemberId);
            queryWrapper.eq("type",0);
            int count = projectListNodeMemberOaMapper.selectCount(queryWrapper);
            if(count>0){
                oaNo = projectListVO.getTaskNo()+"_R"+(count);
            }
        }
        review.setDocSubject(title);
        formValues.put("fd_3dca4ff17c443c",oaNo); //OA单号
        review.setFormValues(formValues);
        review.setFdSource(ProjectConstants.SYSTEM_NAME);
        review.setAttachmentForms(attachmentForms);


        JSONObject res =  oaUtils.addReview3(review);

        logger.info("启动OA项目文件审批流程返回参数:"+res);

        if(res.getBoolean("success")){
            //更新状态 OA单号盒OA id
            JSONObject update = new JSONObject();
            update.put("id",projectNodeMemberId);
            update.put("status", TaskStatusEnum.OA_APPROVE.getStatus());
            update.put("oaNo",oaNo);
            update.put("oaId",res.getString("data"));
            projectListNodeMapper.updateNodeMember(update);


            ProjectListNodeMemberOa projectListNodeMemberOa = new ProjectListNodeMemberOa();
            projectListNodeMemberOa.setProjectListNodeMemberId(Long.valueOf(projectNodeMemberId));
            projectListNodeMemberOa.setOaId(res.getString("data"));
            projectListNodeMemberOa.setOaNo(oaNo);
            projectListNodeMemberOa.setPutOaTime(new Date());
            projectListNodeMemberOa.setStatus(TaskStatusEnum.OA_APPROVE.getStatus());
            projectListNodeMemberOa.setType(type);
            projectListNodeMemberOaMapper.insert(projectListNodeMemberOa);

            return AjaxResult.success(res.getString("data"));
        }else{
            return AjaxResult.error(res.getString("errorInfo"));
        }

    }


    /**
     * OA状态回写
     * @param jsonObject
     * @return
     */
    @Override
    public void projectFileProcessBackStatus(JSONObject jsonObject) {

        if(jsonObject.getIntValue("status") == 0){

            ProjectListNodeMemberVO projectListNodeMemberVO = projectListNodeMapper.queryProjectTaskInfo(jsonObject);
            Date now = new Date();
            Date endDate = DateUtils.dateTime(DateUtils.YYYY_MM_DD,projectListNodeMemberVO.getEndTime());
            if(now.before(endDate)){//未超期
                jsonObject.put("overdue",0);
            }else{
                jsonObject.put("overdue",1);//超期
            }

            Date startDate = DateUtils.dateTime(DateUtils.YYYY_MM_DD,projectListNodeMemberVO.getStartTime());
            int dayNum = DateUtils.differentDaysByMillisecond(startDate,now);
            jsonObject.put("dayNum",dayNum);

            jsonObject.put("workEndTime",now);


            jsonObject.put("statusTask", TaskStatusEnum.DONE.getStatus());

        }else{
            jsonObject.put("statusTask", TaskStatusEnum.OA_REJECT.getStatus());
        }

        //更新OA记录表
        ProjectListNodeMemberOa update = new ProjectListNodeMemberOa();
        update.setStatus(jsonObject.getIntValue("statusTask"));
        update.setUpdateTime(new Date());

        QueryWrapper<ProjectListNodeMemberOa>   queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("oa_id",jsonObject.getString("oaId"));
        projectListNodeMemberOaMapper.update(update,queryWrapper);

        //更新任务表状态
        projectListNodeMapper.projectFileProcessBackStatus(jsonObject);

        //判断是否所有任务已经完成 如完成 则关闭项目
        if(jsonObject.getIntValue("status") == 0){//审核通过
            ProjectListVO projectListVO = projectListNodeMapper.queryProjectInfoByOaId(jsonObject.getString("oaId"));
            checkProjectDone(projectListVO);
        }

    }

    /**
     * 校验项目的任务是否全部完成 如完成 则关闭工单
     * @param projectListVO
     */

    @Override
    public void checkProjectDone(ProjectListVO projectListVO) {
//        JSONObject res = projectListNodeMapper.queryProjectIdByOaId(oaId);
//
//        int unDoneNum = projectListNodeMapper.queryUnDoneNum(res.getLong("projectListId"));

        //计算项目进度
        JSONObject res = projectListService.queryProgress(projectListVO);
        ProjectList projectList = new ProjectList();
        projectList.setId(projectListVO.getId());
        projectList.setUpdateTime(new Date());
        projectList.setProgress(res.getBigDecimal("progress"));
        //如果进度是100
        if(res.getBigDecimal("progress").compareTo(BigDecimal.valueOf(100))==0){
            projectList.setStatus(ProjectListStatusEnum.DONE.getStatus());

            JSONObject param = new JSONObject();
            param.put("projectListId",res.getLong("projectListId"));
            param.put("status",ProjectListStatusEnum.DONE.getStatus());
            param.put("remark","项目完成!");
            param.put("userId",res.getLong("userId"));
            projectListMapper.addLog(param);

        }
        projectListMapper.updateById(projectList);
    }

    /**
     * 查询PRD 流程数据
     * @return
     */
    @Override

    public List queryPRDList(JSONObject param) {
        return oaMapper.queryOAPrdList(param);
    }

    /**
     * 查询PRD 流程的提交人列表
     * @return
     */
    @Override
    @DataSource(DataSourceType.OA)
    public AjaxResult queryPRDUserList() {

        List<JSONObject> list = oaMapper.queryPRDUserList();
        return AjaxResult.success(list);
    }

    /**
     * 发送代办
     * @param obj
     * @return
     */
    @Override
    public AjaxResult sendTodo(JSONObject obj) {

        String url =paramConfig.getOaAddr()+ ProjectConstants.OA_TODO_URL+"sendTodo";

        HttpHeaders headers = new HttpHeaders();

        //表单的形式请求
        headers.setContentType(MediaType.APPLICATION_JSON);
        //请求参数与请求头封装
        HttpEntity<JSONObject> requestEntity = new HttpEntity<>(obj, headers);


        JSONObject res = restTemplate.postForObject(url,requestEntity,JSONObject.class);
        logger.info("创建OA代办返回信息:"+res+" ,请求参数为:"+obj);
        if(res.getIntValue("returnState")==2){
            return AjaxResult.success("操作成功!"+res.getString("message"));
        }

        return AjaxResult.error("操作失败:"+res.getString("message"));
    }

    @Override
    @DataSource(DataSourceType.OA)
    public String queryUserIdByUserNo(String jobNumber) {

        return oaMapper.queryUserIdByUserNo(jobNumber);
    }

    @Override
    public void projectFileMoreBackStatus(JSONObject jsonObject) throws IOException {

        //解析OA传回的文件
        Long sysFileId = null;
        if(StringUtils.isNotBlank(jsonObject.getString("base64File"))){
            String base64String = jsonObject.getString("base64File");
            byte[] decodedBytes = Base64.getDecoder().decode(base64String);
            File outputFile = FileUploadUtils.getAbsoluteFile(paramConfig.getFilePath()+File.separator+"oaBackFile"+File.separator+UUID.randomUUID(),jsonObject.getString("fileName"));
            FileOutputStream fos = new FileOutputStream(outputFile);
            fos.write(decodedBytes);



            String oriFileName = jsonObject.getString("fileName");//原文件名
            String suffix=oriFileName.substring(oriFileName.lastIndexOf("."));//文件后缀
            String newFileName=oriFileName;
            //文件大小
            double sizeKb= Math.round((outputFile.length()/1024.0) * 100) / 100.0;

            //查询用户ID
            SysUser sysUser = sysUserMapper.selectUserByOaUserId(jsonObject.getString("oaUserId"));

            //上传成功记录数据表
            SysFiles sysFiles = new SysFiles();
            sysFileId = YitIdHelper.nextId();
            sysFiles.setId(sysFileId);
            sysFiles.setOriginName(oriFileName);
            sysFiles.setPhysicsName(newFileName);
            sysFiles.setSuffix(suffix);

            String path =outputFile.getAbsolutePath();
            path = path.replace(paramConfig.getFilePath(),"");

            sysFiles.setPath(path);
            sysFiles.setType(FileType.OTHERS.getCode());
            sysFiles.setCreateBy(sysUser==null?null:sysUser.getUserId());
            sysFiles.setCreateTime(LocalDateTime.now());
            sysFiles.setSizeKb(sizeKb);
            sysFiles.setRemark("OA审核回写文件");
            sysFileMapper.insert(sysFiles);
        }


        JSONObject res =  projectListMemberMapper.queryModifyId(jsonObject);
        jsonObject.putAll(res);
        projectListMemberMapper.projectFileMoreBackStatus(jsonObject);
        //文件ID
        if(sysFileId != null){
            Long[] fileIds = {sysFileId};
            res.put("fileIds",fileIds);
            res.put("projectNodeMemberId",res.getLong("projectListNodeMemberId"));
            projectListNodeMapper.addFileMember(res);
        }

        //更新项目进度
        ProjectListVO projectListVO = projectListNodeMapper.queryProjectInfoByOaId(jsonObject.getString("oaId"));
        checkProjectDone(projectListVO);

    }


    /**
     * 多人审核流程结束节点状态回写
     * @param jsonObject
     */
    @Override
    public void projectFileMoreEndBackStatus(JSONObject jsonObject) {
         List<JSONObject> list =  projectListMemberMapper.queryEndTaskId(jsonObject);
        projectListMemberMapper.updateStatus(list);


        //更新项目进度
        ProjectListVO projectListVO = projectListNodeMapper.queryProjectInfoByOaId(jsonObject.getString("oaId"));
        checkProjectDone(projectListVO);
    }


}
